package HLLib.game;

import HLCode.HLClass;
import HLCode.HLClassManager;
import HLCode.HLClassManager_H;
import HLCode.HLObject;
import HLLib.HLLib_H;
import HLLib.base.HLGraphics;
import HLLib.base.HLImage;
import HLLib.base.HLList;
import HLLib.base.HLMath;

public class HLCamera extends HLCameraScaled implements HLMapSprite_H {
    public HLClass GetClass(HLClassManager classManager) {
        return classManager.GetLibClass(HLClassManager_H.CLASS_GROUP_TYPE_LIB_GAME, HLClassManager_H.LIB_CLASS_GAME_Camera);
    }

    public int GetInt(int index) {
        switch (index) {
        case 22: {
            return gridXofMap;
        }
        case 23: {
            return gridYofMap;
        }
        }
        return super.GetInt(index);
    }

    public void SetInt(int index, int value) {
        switch (index) {
        case 22: {
            gridXofMap = (short) value;
            return;
        }
        case 23: {
            gridYofMap = (short) value;
            return;
        }
        }
        super.SetInt(index, value);
    }

    public boolean GetBoolean(int index) {
        switch (index) {
        case 0: {
            return CARMACK_ENABLE;
        }
        case 1: {
            return renderMap;
        }
        }
        return super.GetBoolean(index);
    }

    public void SetBoolean(int index, boolean value) {
        switch (index) {
        case 0: {
            CARMACK_ENABLE = value;
            return;
        }
        case 1: {
            renderMap = value;
            return;
        }
        }
        super.SetBoolean(index, value);
    }

    public HLObject GetObject(int index) {
        return super.GetObject(index);
    }

    public void SetObject(int index, HLObject value) {
        super.SetObject(index, value);
    }

    public boolean CARMACK_ENABLE = true;

    boolean BACKBUFFER_CLIP_ENABLE = false;

    private HLWorld ownerWorld;

    private HLImage buffer;

    private HLGraphics gBuffer;

    /**
     * ???????v??
     */
    private static HLImage mapSpriteBuffer = null;

    /**
     * ???????v??
     */
    private HLGraphics gMapSpriteBuffer;

    // private HLList[] spriteGroups;
    //
    // public short xOfScreen;
    //
    // public short yOfScreen;

    private short bufferWidth;

    private short bufferHeight;

    // public short width;
    //
    // public short height;
    //
    // public short showWidth;
    //
    // public short showHeight;
    //
    // public short xOfWorld;
    //
    // public short yOfWorld;
    //
    // public short xOfFrame;
    //
    // public short yOfFrame;
    //
    // public short realXOfScreen;
    //
    // public short realYOfScreen;

    public short gridXofMap;

    public short gridYofMap;

    // public short maxMoveH;
    //
    // public short maxMoveV;

    private short anchorXOnBuffer;

    private short anchorYOnBuffer;

    private short anchorGridXOnBuffer;

    private short anchorGridYOnBuffer;

    private byte bufferGridCountH;

    private byte bufferGridCountV;

    public boolean renderMap = true;

    public HLCamera(HLWorld ownerWorld) {
        ownerWorldScaled = ownerWorld;
        this.ownerWorld = ownerWorld;
        BACKBUFFER_CLIP_ENABLE = !HLLib_H.USE_NOKIA_UI;
        ClearSprite();
        if (CARMACK_ENABLE && !BACKBUFFER_CLIP_ENABLE) {
            createMapSpriteBuffer();
        }
    }

    public HLCamera() {
    }

    // ClearSprite
    // void ClearSprite() {
    // spriteGroups = new HLList[SPRITE_PRI_COUNT];
    // for (int i = 0; i < SPRITE_PRI_COUNT; i++) {
    // spriteGroups[i] = new HLList();
    // }
    // }

    // AddSprite
    // void AddSprite(HLSprite sprite) {
    // // ??????????????
    // if (IsSpriteOut(sprite)) {
    // sprite.onScreen = false;
    // return;
    // }
    // sprite.onScreen = true;
    //
    // if (ownerWorld.WORLD_IS_3D) {
    // int priority = sprite.pri;
    //
    // // ????
    // HLList spriteGroup = spriteGroups[priority];
    // int insertPos = spriteGroup.items.length;
    //
    // if (priority == SPRITE_PRI_NORMAL) {
    // for (int i = 0; i < insertPos; i++) {
    // if (sprite.yFP <= ((HLSprite) spriteGroup.items[i]).yFP) {
    // insertPos = i;
    // break;
    // }
    // }
    // }
    //
    // // ????
    // spriteGroup.Insert(insertPos, sprite);
    // } else {
    // // ????
    // //
    // ???????????????????????????????????????????????????????????????Y????SPRITE_PRI_HIGHER??????
    // // ????????????????????????????1????????
    // HLList spriteGroup = spriteGroups[SPRITE_PRI_HIGHER];
    // int insertPos = spriteGroup.items.length;
    // for (int i = 0; i < insertPos; i++) {
    // if (sprite.pri <= ((HLSprite) spriteGroup.items[i]).pri) {
    // insertPos = i;
    // break;
    // }
    // }
    //
    // // ????
    // spriteGroup.Insert(insertPos, sprite);
    // }
    // }

    // // IsSpriteOut
    // public boolean IsSpriteOut(HLSprite sprite) {
    // if (ownerWorld.WORLD_IS_3D) {
    // return (!sprite.visibled //
    // || sprite.x + sprite.area.x >= xOfWorld + showWidth //
    // || sprite.x + sprite.area.x + sprite.area.width <= xOfWorld //
    // || sprite.y - sprite.z + sprite.area.y >= yOfWorld + showHeight //
    // || sprite.y - sprite.z + sprite.area.y + sprite.area.height <= yOfWorld);
    // } else {
    // return (!sprite.visibled //
    // || sprite.x + sprite.area.x >= xOfWorld + showWidth //
    // || sprite.x + sprite.area.x + sprite.area.width <= xOfWorld //
    // || sprite.y + sprite.area.y >= yOfWorld + showHeight //
    // || sprite.y + sprite.area.y + sprite.area.height <= yOfWorld);
    // }
    // }

    // KillBuffer
    void KillBuffer() {
        if (CARMACK_ENABLE) {
            gBuffer = null;
            buffer = null;
        }
    }

    // GetBuffer
    void GetBuffer(int width, int height) {
        if (CARMACK_ENABLE) {
            bufferWidth = (short) width;

            bufferHeight = (short) height;

            buffer = HLImage.CreateImageBySize(width, height);

            gBuffer = buffer.GetGraphics();
        }
    }

    // Clear
    void Clear() {
        if (CARMACK_ENABLE) {
            KillBuffer();
        }

        ClearSprite();

        if (CARMACK_ENABLE) {
            bufferGridCountH = 0;
            bufferGridCountV = 0;
        }

        width = 0;
        height = 0;
        showWidth = 0;
        showHeight = 0;
        xOfWorld = 0;
        yOfWorld = 0;
        gridXofMap = 0;
        gridYofMap = 0;
        maxMoveH = 0;
        maxMoveV = 0;
        xOfFrame = 0;
        yOfFrame = 0;

        if (CARMACK_ENABLE) {
            anchorXOnBuffer = 0;
            anchorYOnBuffer = 0;
            anchorGridXOnBuffer = 0;
            anchorGridYOnBuffer = 0;
        }
    }

    /**
     * ?????????????????????
     */
    private final void createMapSpriteBuffer() {
        if (CARMACK_ENABLE && !BACKBUFFER_CLIP_ENABLE) {
            if (ownerWorld.mapSpriteMaxOccupyH > 0 && ownerWorld.mapSpriteMaxOccupyV > 0) {

                int tempWidth = ownerWorld.mapSpriteMaxOccupyH * ownerWorld.gridWidth;
                int tempHeight = ownerWorld.mapSpriteMaxOccupyV * ownerWorld.gridHeight;

                int oldWidth = 0;
                int oldHeight = 0;

                if (null != mapSpriteBuffer) {
                    oldWidth = mapSpriteBuffer.GetWidth();
                    oldHeight = mapSpriteBuffer.GetHeight();
                }

                if (tempWidth > oldWidth || tempHeight > oldHeight) {
                    gMapSpriteBuffer = null;

                    mapSpriteBuffer = null;

                    mapSpriteBuffer = HLImage.CreateImageBySize(Math.max(tempWidth, oldWidth), Math.max(tempHeight, oldHeight));

                    gMapSpriteBuffer = mapSpriteBuffer.GetGraphics();
                }
            }
        }
    }

    // SetPosOfScreen
    // public void SetPosOfScreen(int x, int y) {
    // xOfScreen = (short) x;
    // yOfScreen = (short) y;
    //
    // RefreshRealPos();
    // }

    // MoveOfScreen
    // public void MoveOfScreen(int dx, int dy) {
    // xOfScreen += (short) dx;
    // yOfScreen += (short) dy;
    //
    // RefreshRealPos();
    // }

    // RefreshRealPos
    public void RefreshRealPos() {
        realXOfScreen = (short) (xOfScreen + xOfFrame);
        realYOfScreen = (short) (yOfScreen + yOfFrame);
    }

    public int WorldXToScreen(int x) {
        return (shakeOffsetX + realXOfScreen - xOfWorld + x);
    }

    public int WorldYToScreen(int y) {
        return (shakeOffsetY + realYOfScreen - yOfWorld + y);
    }

    public int ScreenXToWorld(int x) {
        return (x - shakeOffsetX - realXOfScreen + xOfWorld);
    }

    public int ScreenYToWorld(int y) {
        return (y - shakeOffsetY - realYOfScreen + yOfWorld);
    }

    // SetSize
    public void SetSize(int width, int height) {
        if (CARMACK_ENABLE) {
            KillBuffer();
        }

        ClearSprite();

        this.width = (short) width;
        this.height = (short) height;

        if (CARMACK_ENABLE) {
            bufferGridCountH = (byte) (width >= ownerWorld.width - ownerWorld.gridWidth ? //
            ownerWorld.gridCountH
                    : //
                    (width + ownerWorld.gridWidth - 1) / ownerWorld.gridWidth + 1);

            bufferGridCountV = (byte) (height >= ownerWorld.height - ownerWorld.gridHeight ? //
            ownerWorld.gridCountV
                    : //
                    (height + ownerWorld.gridHeight - 1) / ownerWorld.gridHeight + 1);

            GetBuffer(bufferGridCountH * ownerWorld.gridWidth, bufferGridCountV * ownerWorld.gridHeight);
        }

        showWidth = (short) Math.min(width, ownerWorld.width);
        showHeight = (short) Math.min(height, ownerWorld.height);

        maxMoveH = (ownerWorld.width - width);
        if (maxMoveH < 0) {
            xOfFrame = (short) (-maxMoveH >> 1);
            maxMoveH = 0;
        } else {
            xOfFrame = 0;
        }

        maxMoveV = (ownerWorld.height - height);
        if (maxMoveV < 0) {
            yOfFrame = (short) (-maxMoveV >> 1);
            maxMoveV = 0;
        } else {
            yOfFrame = 0;
        }

        RefreshRealPos();

        if (CARMACK_ENABLE) {
            BufferRefreshAll();
        }
    }

    // SetPos
    public void SetPos(int x, int y) {
        if (x <= 0) {
            x = 0;
        } else if (x > maxMoveH) {
            x = maxMoveH;
        }

        if (y <= 0) {
            y = 0;
        } else if (y > maxMoveV) {
            y = maxMoveV;
        }

        if (x == xOfWorld && y == yOfWorld) {
            return;
        }
        {
            int dx = x - xOfWorld;
            int dy = y - yOfWorld;
            xOfWorld = x;
            yOfWorld = y;

            gridXofMap = (short) (xOfWorld / ownerWorld.gridWidth);
            gridYofMap = (short) (yOfWorld / ownerWorld.gridHeight);

            if (CARMACK_ENABLE) {

                int oldAnchorGridXOnBuffer = anchorGridXOnBuffer;
                int oldAnchorGridYOnBuffer = anchorGridYOnBuffer;

                anchorXOnBuffer += (short) dx;
                anchorGridXOnBuffer = (short) (anchorXOnBuffer >= 0 ? anchorXOnBuffer / ownerWorld.gridWidth : (anchorXOnBuffer + 1) / ownerWorld.gridWidth - 1);

                anchorYOnBuffer += (short) dy;
                anchorGridYOnBuffer = (short) (anchorYOnBuffer >= 0 ? anchorYOnBuffer / ownerWorld.gridHeight : (anchorYOnBuffer + 1) / ownerWorld.gridHeight - 1);

                int dGridx = anchorGridXOnBuffer - oldAnchorGridXOnBuffer;
                int dGridy = anchorGridYOnBuffer - oldAnchorGridYOnBuffer;

                if (dGridx == 0 && dGridy == 0) {
                    return;
                }

                if (Math.abs(dGridx) >= bufferGridCountH || Math.abs(dGridy) >= bufferGridCountV) {
                    BufferRefreshAll();
                } else {
                    int gridX0 = -1;
                    int gridX1 = -1;
                    int gridX2 = -1;
                    int gridX3 = -1;

                    int gridX0ofY;
                    int gridX1ofY;
                    int gridX2ofY = -1;
                    int gridX3ofY = -1;

                    if (dGridx > 0) {
                        gridX0 = oldAnchorGridXOnBuffer;
                        if (anchorGridXOnBuffer >= bufferGridCountH) {
                            anchorXOnBuffer -= bufferWidth;
                            anchorGridXOnBuffer -= bufferGridCountH;
                            gridX1 = bufferGridCountH - 1;
                            gridX2 = 0;
                            gridX3 = anchorGridXOnBuffer - 1;

                            gridX0ofY = anchorGridXOnBuffer;
                            gridX1ofY = oldAnchorGridXOnBuffer - 1;
                        } else {
                            gridX1 = anchorGridXOnBuffer - 1;

                            gridX0ofY = 0;
                            gridX1ofY = oldAnchorGridXOnBuffer - 1;
                            gridX2ofY = anchorGridXOnBuffer;
                            gridX3ofY = bufferGridCountH - 1;
                        }
                    } else if (dGridx < 0) {
                        gridX3 = oldAnchorGridXOnBuffer - 1;
                        if (anchorGridXOnBuffer < 0) {
                            anchorXOnBuffer += bufferWidth;
                            anchorGridXOnBuffer += bufferGridCountH;
                            gridX2 = 0;
                            gridX1 = bufferGridCountH - 1;
                            gridX0 = anchorGridXOnBuffer;

                            gridX0ofY = oldAnchorGridXOnBuffer;
                            gridX1ofY = anchorGridXOnBuffer - 1;
                        } else {
                            gridX2 = anchorGridXOnBuffer;

                            gridX0ofY = 0;
                            gridX1ofY = anchorGridXOnBuffer - 1;
                            gridX2ofY = oldAnchorGridXOnBuffer;
                            gridX3ofY = bufferGridCountH - 1;
                        }
                    } else {
                        gridX0ofY = 0;
                        gridX1ofY = anchorGridXOnBuffer - 1;
                        gridX2ofY = anchorGridXOnBuffer;
                        gridX3ofY = bufferGridCountH - 1;
                    }

                    {
                        int gridY0 = -1;
                        int gridY1 = -1;
                        int gridY2 = -1;
                        int gridY3 = -1;
                        if (dGridy > 0) {
                            gridY0 = oldAnchorGridYOnBuffer;
                            if (anchorGridYOnBuffer >= bufferGridCountV) {
                                anchorYOnBuffer -= bufferHeight;
                                anchorGridYOnBuffer -= bufferGridCountV;
                                gridY1 = bufferGridCountV - 1;
                                gridY2 = 0;
                                gridY3 = anchorGridYOnBuffer - 1;
                            } else {
                                gridY1 = anchorGridYOnBuffer - 1;
                            }
                        } else if (dGridy < 0) {
                            gridY3 = oldAnchorGridYOnBuffer - 1;
                            if (anchorGridYOnBuffer < 0) {
                                anchorYOnBuffer += bufferHeight;
                                anchorGridYOnBuffer += bufferGridCountV;
                                gridY2 = 0;
                                gridY1 = bufferGridCountV - 1;
                                gridY0 = anchorGridYOnBuffer;
                            } else {
                                gridY2 = anchorGridYOnBuffer;
                            }
                        }

                        if (gridX0 >= 0) {
                            BufferRefresh(gridX0, 0, gridX1, anchorGridYOnBuffer - 1);
                            BufferRefresh(gridX0, anchorGridYOnBuffer, gridX1, bufferGridCountV - 1);
                        }
                        if (gridX2 >= 0) {
                            BufferRefresh(gridX2, 0, gridX3, anchorGridYOnBuffer - 1);
                            BufferRefresh(gridX2, anchorGridYOnBuffer, gridX3, bufferGridCountV - 1);
                        }
                        if (gridY0 >= 0) {
                            if (gridX0ofY >= 0) {
                                BufferRefresh(gridX0ofY, gridY0, gridX1ofY, gridY1);
                            }
                            if (gridX2ofY >= 0) {
                                BufferRefresh(gridX2ofY, gridY0, gridX3ofY, gridY1);
                            }
                        }
                        if (gridY2 >= 0) {
                            if (gridX0ofY >= 0) {
                                BufferRefresh(gridX0ofY, gridY2, gridX1ofY, gridY3);
                            }
                            if (gridX2ofY >= 0) {
                                BufferRefresh(gridX2ofY, gridY2, gridX3ofY, gridY3);
                            }
                        }
                    }
                }
            }
        }
    }

    // public void Move(int dx, int dy) {
    // SetPos(xOfWorld + (dx), yOfWorld + (dy));
    // }

    // public void SetCenter(int x, int y) {
    // SetPos(x - (showWidth >> 1), y - (showHeight >> 1));
    // }

    // SetCenterBufferEX
    // public void SetCenterBufferEX(int x, int y, int percentX, int percentY,
    // int dxMin, int dyMin) {
    // x -= (showWidth >> 1);
    // y -= (showHeight >> 1);
    // {
    // int dx = 0;
    // if (x != xOfWorld) {
    // dx = (x - xOfWorld) * percentX / 100;
    // if (Math.abs(dx) < dxMin) {
    // dx = x < xOfWorld ? -dxMin : dxMin;
    // }
    // }
    // int dy = 0;
    // if (y != yOfWorld) {
    // dy = (y - yOfWorld) * percentY / 100;
    // if (Math.abs(dy) < dyMin) {
    // dy = y < yOfWorld ? -dyMin : dyMin;
    // }
    // }
    // SetPos(xOfWorld + dx, yOfWorld + dy);
    // }
    // }

    // public void SetCenterBuffer(int x, int y, int percentX, int percentY) {
    // SetCenterBufferEX(x, y, percentX, percentY, 1, 1);
    // }

    // public int CenterX() {
    // return (xOfWorld + (showWidth >> 1));
    // }

    // public int CenterY() {
    // return (yOfWorld + (showHeight >> 1));
    // }

    // public boolean IsOnPos(int x, int y) {
    // return (xOfWorld == x && yOfWorld == y);
    // }

    // IsOnCenter
    // public boolean IsOnCenter(int x, int y) {
    // x -= (showWidth >> 1);
    // y -= (showHeight >> 1);
    // return (xOfWorld == x || (x <= 0 && xOfWorld == 0) || (x + showWidth >=
    // ownerWorld.width && xOfWorld + showWidth == ownerWorld.width)) &&
    // (yOfWorld == y || (y <= 0 && yOfWorld == 0) || (y + showHeight >=
    // ownerWorld.height && yOfWorld + showHeight == ownerWorld.height));
    // }

    // BufferRefresh
    void BufferRefresh(int gridX0, int gridY0, int gridX1, int gridY1) {
        if (CARMACK_ENABLE) {
            if (gridX0 > gridX1 || gridY0 > gridY1) {
                return;
            }

            {
                int yStart = gridY0 * ownerWorld.gridHeight;
                int gridYonMapStart;

                if (gridY0 >= anchorGridYOnBuffer) {
                    gridYonMapStart = gridY0 + gridYofMap - anchorGridYOnBuffer;
                    gridY1 += gridYofMap - anchorGridYOnBuffer;
                } else {
                    gridYonMapStart = gridY0 + gridYofMap - anchorGridYOnBuffer + bufferGridCountV;
                    gridY1 += gridYofMap - anchorGridYOnBuffer + bufferGridCountV;
                }

                if (gridY1 >= ownerWorld.gridCountV) {
                    gridY1 = ownerWorld.gridCountV - 1;
                }

                int xStart = gridX0 * ownerWorld.gridWidth;
                int gridXonMapStart;

                if (gridX0 >= anchorGridXOnBuffer) {
                    gridXonMapStart = gridX0 + gridXofMap - anchorGridXOnBuffer;
                    gridX1 += gridXofMap - anchorGridXOnBuffer;
                } else {
                    gridXonMapStart = gridX0 + gridXofMap - anchorGridXOnBuffer + bufferGridCountH;
                    gridX1 += gridXofMap - anchorGridXOnBuffer + bufferGridCountH;
                }
                if (gridX1 >= ownerWorld.gridCountH) {
                    gridX1 = ownerWorld.gridCountH - 1;
                }

                int y = yStart;
                gridY0 = gridYonMapStart;
                while (gridY0 <= gridY1) {
                    // HLGrid * line = ownerWorld.gridRows[gridY0];
                    int x = xStart;
                    gridX0 = gridXonMapStart;
                    while (gridX0 <= gridX1) {
                        gBuffer.DrawImage(((HLTile) ownerWorld.tiles.items[ownerWorld.Grid_GetTileType(gridX0, gridY0)]).image, x, y, ownerWorld.Grid_GetTileTrans(gridX0, gridY0));
                        x += ownerWorld.gridWidth;
                        gridX0++;
                    }
                    y += ownerWorld.gridHeight;
                    gridY0++;
                }

                // ???????????
                if (ownerWorld.mapSpritePriorityEnable != null) {
                    int clipX = xStart;
                    int clipY = yStart;
                    int clipWidth = (gridX1 - gridXonMapStart + 1) * ownerWorld.gridWidth;
                    int clipHeight = (gridY1 - gridYonMapStart + 1) * ownerWorld.gridHeight;

                    int clipGridX0 = gridXonMapStart;
                    int clipGridY0 = gridYonMapStart;
                    int clipGridX1 = gridX1;
                    int clipGridY1 = gridY1;

                    if (BACKBUFFER_CLIP_ENABLE) {// ??????????????????????????????????
                        gBuffer.SetClip(xStart, yStart, (clipGridX1 - clipGridX0 + 1) * ownerWorld.gridWidth, (clipGridY1 - clipGridY0 + 1) * ownerWorld.gridHeight);
                    }

                    gridYonMapStart -= ownerWorld.mapSpriteMaxCheckToUp;
                    yStart -= ownerWorld.mapSpriteMaxCheckToUp * ownerWorld.gridHeight;
                    if (gridYonMapStart < 0) {
                        yStart += -gridYonMapStart * ownerWorld.gridHeight;
                        gridYonMapStart = 0;
                    }

                    gridY1 += ownerWorld.mapSpriteMaxCheckToDown;
                    if (gridY1 >= ownerWorld.gridCountV) {
                        gridY1 = ownerWorld.gridCountV - 1;
                    }

                    gridXonMapStart -= ownerWorld.mapSpriteMaxCheckToLeft;
                    xStart -= ownerWorld.mapSpriteMaxCheckToLeft * ownerWorld.gridWidth;
                    if (gridXonMapStart < 0) {
                        xStart += -gridXonMapStart * ownerWorld.gridWidth;
                        gridXonMapStart = 0;
                    }

                    gridX1 += ownerWorld.mapSpriteMaxCheckToRight;
                    if (gridX1 >= ownerWorld.gridCountH) {
                        gridX1 = ownerWorld.gridCountH - 1;
                    }

                    for (int priority = 0; priority < MAPSPRITE_PRI_COUNT; ++priority) {
                        if (!ownerWorld.mapSpritePriorityEnable[priority]) {
                            continue;
                        }
                        y = yStart;
                        gridY0 = gridYonMapStart;

                        while (gridY0 <= gridY1) {
                            int x = xStart;
                            gridX0 = gridXonMapStart;
                            while (gridX0 <= gridX1) {
                                if (ownerWorld.Grid_GetHasMapSprite(gridX0, gridY0)) {
                                    // int tempMapSpriteType =
                                    // ownerWorld.Grid_GetMapSpriteType(gridX0,
                                    // gridY0);
                                    HLMapSprite tempMapSpriteModel = (HLMapSprite) ownerWorld.mapSprites.items[ownerWorld.Grid_GetMapSpriteType(gridX0, gridY0)];

                                    if (priority == tempMapSpriteModel.pri //
                                            && gridX0 - tempMapSpriteModel.occupyH <= clipGridX1 //
                                            && gridX0 + tempMapSpriteModel.gridCountH + tempMapSpriteModel.occupyH > clipGridX0 //
                                            && gridY0 - tempMapSpriteModel.occupyV <= clipGridY1 //
                                            && gridY0 + tempMapSpriteModel.gridCountV > clipGridY0) {
                                        if (BACKBUFFER_CLIP_ENABLE) {
                                            gBuffer.DrawImageAdjustable(
                                            //
                                                    tempMapSpriteModel.image,//
                                                    x,//
                                                    y,//
                                                    ownerWorld.gridWidth * tempMapSpriteModel.gridCountH,//
                                                    ownerWorld.gridHeight * tempMapSpriteModel.gridCountV - tempMapSpriteModel.offset,//
                                                    ownerWorld.Grid_GetMapSpriteTrans(gridX0, gridY0),//
                                                    HCENTER_BOTTOM);
                                        } else {
                                            gBuffer.SetClip(clipX, clipY, clipWidth, clipHeight);

                                            int tempMapSpriteTrans = ownerWorld.Grid_GetMapSpriteTrans(gridX0, gridY0);
                                            if (tempMapSpriteTrans == TRANS_NONE) {
                                                gBuffer.DrawImageAdjustable(
                                                //
                                                        tempMapSpriteModel.image,//
                                                        x,//
                                                        y,//
                                                        ownerWorld.gridWidth * tempMapSpriteModel.gridCountH,//
                                                        ownerWorld.gridHeight * tempMapSpriteModel.gridCountV - tempMapSpriteModel.offset,//
                                                        TRANS_NONE,//
                                                        HCENTER_BOTTOM);
                                            } else {
                                                int tempOccupyWidth = ownerWorld.gridWidth * (tempMapSpriteModel.gridCountH + (tempMapSpriteModel.occupyH << 1));
                                                int tempOccupyHeight = ownerWorld.gridHeight * (tempMapSpriteModel.gridCountV + tempMapSpriteModel.occupyV) - tempMapSpriteModel.offset;

                                                int mapSpriteBufferPosOnBufferX = x - ownerWorld.gridWidth * tempMapSpriteModel.occupyH;

                                                int mapSpriteBufferPosOnBufferY = y - ownerWorld.gridHeight * tempMapSpriteModel.occupyV;

                                                if (//
                                                mapSpriteBufferPosOnBufferX < clipX || //
                                                        mapSpriteBufferPosOnBufferY < clipY || //
                                                        mapSpriteBufferPosOnBufferX + tempOccupyWidth > clipX + clipWidth || //
                                                        mapSpriteBufferPosOnBufferY + tempOccupyHeight > clipY + clipHeight) {
                                                    gMapSpriteBuffer.SetClip(
                                                    //
                                                            0, //
                                                            0,//
                                                            tempOccupyWidth,//
                                                            tempOccupyHeight//
                                                            );
                                                    gMapSpriteBuffer.ClipRect(clipX - mapSpriteBufferPosOnBufferX, clipY - mapSpriteBufferPosOnBufferY, clipWidth, clipHeight);
                                                    gMapSpriteBuffer.DrawImage(buffer, -mapSpriteBufferPosOnBufferX, -mapSpriteBufferPosOnBufferY, 0);

                                                    gMapSpriteBuffer.DrawImageAdjustable(
                                                    //
                                                            tempMapSpriteModel.image, //
                                                            0,//
                                                            0,//
                                                            tempOccupyWidth,//
                                                            tempOccupyHeight,//
                                                            tempMapSpriteTrans,//
                                                            HCENTER_BOTTOM//
                                                            );

                                                    gBuffer.ClipRect(mapSpriteBufferPosOnBufferX, mapSpriteBufferPosOnBufferY, tempOccupyWidth, tempOccupyHeight);

                                                    gBuffer.DrawImage(mapSpriteBuffer, mapSpriteBufferPosOnBufferX, mapSpriteBufferPosOnBufferY, 0);
                                                } else {
                                                    gBuffer.DrawImageAdjustable(
                                                    //
                                                            tempMapSpriteModel.image, //
                                                            mapSpriteBufferPosOnBufferX,//
                                                            mapSpriteBufferPosOnBufferY,//
                                                            tempOccupyWidth,//
                                                            tempOccupyHeight,//
                                                            tempMapSpriteTrans,//
                                                            HCENTER_BOTTOM//
                                                    );
                                                }
                                            }
                                        }
                                    }
                                }
                                x += ownerWorld.gridWidth;
                                gridX0++;
                            }
                            y += ownerWorld.gridHeight;
                            gridY0++;
                        }
                    }
                    gBuffer.SetClip(0, 0, bufferWidth, bufferHeight);
                }
            }
        }
    }

    // BufferRefreshAll
    void BufferRefreshAll() {
        if (CARMACK_ENABLE) {
            anchorXOnBuffer = (short) (xOfWorld % bufferWidth);
            anchorYOnBuffer = (short) (yOfWorld % bufferHeight);
            anchorGridXOnBuffer = (short) (anchorXOnBuffer / ownerWorld.gridWidth);
            anchorGridYOnBuffer = (short) (anchorYOnBuffer / ownerWorld.gridHeight);

            BufferRefresh(0, 0, anchorGridXOnBuffer - 1, anchorGridYOnBuffer - 1);

            BufferRefresh(anchorGridXOnBuffer, 0, bufferGridCountH - 1, anchorGridYOnBuffer - 1);

            BufferRefresh(0, anchorGridYOnBuffer, anchorGridXOnBuffer - 1, bufferGridCountV - 1);

            BufferRefresh(anchorGridXOnBuffer, anchorGridYOnBuffer, bufferGridCountH - 1, bufferGridCountV - 1);
        }
    }

    // AreaOfMapBufferRefresh
    void AreaOfMapBufferRefresh(int gridX0, int gridY0, int gridX1, int gridY1) {
        if (CARMACK_ENABLE) {
            gridX0 -= gridXofMap;
            gridY0 -= gridYofMap;
            gridX1 -= gridXofMap;
            gridY1 -= gridYofMap;

            if (gridX0 < 0) {
                gridX0 = 0;
            }
            if (gridX1 >= bufferGridCountH) {
                gridX1 = bufferGridCountH - 1;
            }

            if (gridY0 < 0) {
                gridY0 = 0;
            }
            if (gridY1 >= bufferGridCountV) {
                gridY1 = bufferGridCountV - 1;
            }

            if (gridX0 > gridX1 || gridY0 > gridY1) {
                return;
            }

            {
                int gridXofBuffer0 = gridX0 + anchorGridXOnBuffer;
                int gridXofBuffer1 = gridX1 + anchorGridXOnBuffer;

                if (gridXofBuffer1 >= bufferGridCountH) {
                    gridXofBuffer1 -= bufferGridCountH;
                    if (gridXofBuffer0 >= bufferGridCountH) {
                        gridXofBuffer0 -= bufferGridCountH;
                    }
                }

                int gridYofBuffer0 = gridY0 + anchorGridYOnBuffer;
                int gridYofBuffer1 = gridY1 + anchorGridYOnBuffer;

                if (gridYofBuffer1 >= bufferGridCountV) {
                    gridYofBuffer1 -= bufferGridCountV;
                    if (gridYofBuffer0 >= bufferGridCountV) {
                        gridYofBuffer0 -= bufferGridCountV;
                    }
                }

                if (gridXofBuffer0 > gridXofBuffer1) {
                    if (gridYofBuffer0 > gridYofBuffer1) {
                        BufferRefresh(0, 0, gridXofBuffer1, gridYofBuffer1);
                        BufferRefresh(gridXofBuffer0, 0, bufferGridCountH - 1, gridYofBuffer1);
                        BufferRefresh(0, gridYofBuffer0, gridXofBuffer1, bufferGridCountV - 1);
                        BufferRefresh(gridXofBuffer0, gridYofBuffer0, bufferGridCountH - 1, bufferGridCountV - 1);
                    } else {
                        BufferRefresh(0, gridYofBuffer0, gridXofBuffer1, gridYofBuffer1);
                        BufferRefresh(gridXofBuffer0, gridYofBuffer0, bufferGridCountH - 1, gridYofBuffer1);
                    }
                } else {
                    if (gridYofBuffer0 > gridYofBuffer1) {
                        BufferRefresh(gridXofBuffer0, 0, gridXofBuffer1, gridYofBuffer1);
                        BufferRefresh(gridXofBuffer0, gridYofBuffer0, gridXofBuffer1, bufferGridCountV - 1);
                    } else {
                        BufferRefresh(gridXofBuffer0, gridYofBuffer0, gridXofBuffer1, gridYofBuffer1);
                    }
                }
            }
        }
    }

    // RenderEx
    public void RenderEx(HLGraphics g, int offsetX, int offsetY) {
        shakeOffsetX = (byte) offsetX;
        shakeOffsetY = (byte) offsetY;

        g.StoreClip();

        g.ClipRect(realXOfScreen, realYOfScreen, showWidth, showHeight);

        offsetX += realXOfScreen;
        offsetY += realYOfScreen;

        if (CARMACK_ENABLE) {
            if (renderMap) {
                // ??????????????4??camera??????1
                g.DrawRegion(buffer, anchorXOnBuffer, anchorYOnBuffer, bufferWidth - anchorXOnBuffer, bufferHeight - anchorYOnBuffer, offsetX, offsetY);
                // ??????????????2??camera??????3
                g.DrawRegion(buffer, anchorXOnBuffer, 0, bufferWidth - anchorXOnBuffer, anchorYOnBuffer, offsetX, offsetY + bufferHeight - anchorYOnBuffer);
                // ??????????????1??camera??????4
                g.DrawRegion(buffer, 0, 0, anchorXOnBuffer, anchorYOnBuffer, offsetX + bufferWidth - anchorXOnBuffer, offsetY + bufferHeight - anchorYOnBuffer);
                // ??????????????3??camera??????2
                g.DrawRegion(buffer, 0, anchorYOnBuffer, anchorXOnBuffer, bufferHeight - anchorYOnBuffer, offsetX + bufferWidth - anchorXOnBuffer, offsetY);
            } else {
                // g.FillRect(0, 0, HLScreen.width, HLScreen.height, backColor);
            }

            {
                // ?????????????????
                int tempXOfScreen = offsetX - xOfWorld;
                int tempYOfScreen = offsetY - yOfWorld;

                for (int priority = ownerWorld.SPRITE_PRI_START; priority <= ownerWorld.SPRITE_PRI_END; ++priority) {
                    boolean[] tempMapSpritePriorityEnable = ownerWorld.mapSpritePriorityEnableTable[priority];

                    boolean drawMapSprite = tempMapSpritePriorityEnable[FIELD_MAPSPRITE_PRIORITY_ENABLE] && renderMap;

                    HLList spriteGroup = spriteGroups[priority];

                    for (int i = 0; i < spriteGroup.items.length; ++i) {
                        HLSprite tempSprite = (HLSprite) spriteGroup.items[i];
                        if (ownerWorld.WORLD_IS_3D) {
                            tempSprite.Render3D(g, tempXOfScreen, tempYOfScreen);
                        } else {
                            tempSprite.Render2D(g, tempXOfScreen, tempYOfScreen);
                        }

                        if (drawMapSprite) {
                            int oldClipX = g.GetClipX();
                            int oldClipY = g.GetClipY();
                            int oldClipWidth = g.GetClipWidth();
                            int oldClipHeight = g.GetClipHeight();

                            g.ClipRect(//
                                    tempSprite.x + tempSprite.area.x + tempXOfScreen, //
                                    tempSprite.y + tempSprite.area.y + tempYOfScreen - tempSprite.z, //
                                    tempSprite.area.width, //
                                    tempSprite.area.height //
                            );
                            {
                                int startGridX = (tempSprite.x + tempSprite.area.x) / ownerWorld.gridWidth;
                                int startGridY = (tempSprite.y + tempSprite.area.y) / ownerWorld.gridHeight;
                                int endGridX = (tempSprite.x + tempSprite.area.x + tempSprite.area.width - 1) / ownerWorld.gridWidth;
                                int endGridY = (tempSprite.y + tempSprite.area.y + tempSprite.area.height - 1) / ownerWorld.gridHeight;

                                // ????
                                // ????????????????????????????????????????
                                if (SPRITE_PRI_LOWEST >= ownerWorld.SPRITE_PRI_START && SPRITE_PRI_LOWEST <= ownerWorld.SPRITE_PRI_END && ownerWorld.IS_PRIORITY_LOW_MAPSPRITE_ENABLE && tempMapSpritePriorityEnable[MAPSPRITE_PRI_LOW]) {
                                    DrawMapSpriteToScreen(g, tempXOfScreen, tempYOfScreen, startGridX, startGridY, endGridX, endGridY, MAPSPRITE_PRI_LOW, tempSprite);
                                }

                                // ??????????????????????????????????????????????????????????????????
                                if ((SPRITE_PRI_LOWEST >= ownerWorld.SPRITE_PRI_START && SPRITE_PRI_LOWEST <= ownerWorld.SPRITE_PRI_END //
                                        || //
                                        SPRITE_PRI_LOWER >= ownerWorld.SPRITE_PRI_START && SPRITE_PRI_LOWER <= ownerWorld.SPRITE_PRI_END //
                                || //
                                        SPRITE_PRI_NORMAL >= ownerWorld.SPRITE_PRI_START && SPRITE_PRI_NORMAL <= ownerWorld.SPRITE_PRI_END //
                                        )
                                        && ownerWorld.IS_PRIORITY_NORMAL_MAPSPRITE_ENABLE && tempMapSpritePriorityEnable[MAPSPRITE_PRI_NORMAL]) {
                                    DrawMapSpriteToScreen(g, tempXOfScreen, tempYOfScreen, startGridX, !(SPRITE_PRI_NORMAL >= ownerWorld.SPRITE_PRI_START && SPRITE_PRI_NORMAL <= ownerWorld.SPRITE_PRI_END && priority == SPRITE_PRI_NORMAL) ? startGridY : ((tempSprite.y / ownerWorld.gridHeight + (((tempSprite.y % ownerWorld.gridHeight) << 1) >= ownerWorld.gridHeight ? 1 : 0))), endGridX, endGridY, MAPSPRITE_PRI_NORMAL, tempSprite);
                                }

                                // ???????????????????????????????????????????????????????????????????????????
                                if ((SPRITE_PRI_LOWEST >= ownerWorld.SPRITE_PRI_START && SPRITE_PRI_LOWEST <= ownerWorld.SPRITE_PRI_END || SPRITE_PRI_LOWER >= ownerWorld.SPRITE_PRI_START && SPRITE_PRI_LOWER <= ownerWorld.SPRITE_PRI_END || SPRITE_PRI_NORMAL >= ownerWorld.SPRITE_PRI_START && SPRITE_PRI_NORMAL <= ownerWorld.SPRITE_PRI_END || SPRITE_PRI_HIGHER >= ownerWorld.SPRITE_PRI_START && SPRITE_PRI_HIGHER <= ownerWorld.SPRITE_PRI_END) && ownerWorld.IS_PRIORITY_HIGH_MAPSPRITE_ENABLE && tempMapSpritePriorityEnable[MAPSPRITE_PRI_HIGH]) {
                                    DrawMapSpriteToScreen(g, tempXOfScreen, tempYOfScreen, startGridX, startGridY, endGridX, endGridY, MAPSPRITE_PRI_HIGH, tempSprite);
                                }

                                g.SetClip(oldClipX, oldClipY, oldClipWidth, oldClipHeight);
                            }
                        }
                    }
                }
            }
        } else {
            int//
            gridWidth = ownerWorld.gridWidth, //
            gridHeight = ownerWorld.gridHeight;

            int//
            startX = offsetX - (xOfWorld % gridWidth), //
            startY = offsetY - (yOfWorld % gridHeight), //
            startGridX = gridXofMap, //
            startGridY = gridYofMap, //
            endGridX = (xOfWorld + showWidth - 1) / gridWidth, //
            endGridY = (yOfWorld + showHeight - 1) / gridHeight;

            int clipGridX0 = startGridX;
            int clipGridX1 = endGridX;
            int clipGridY0 = startGridY;
            int clipGridY1 = endGridY;

            // ???????
            if (renderMap) {
                int y = startY;
                int gridY = startGridY;
                for (; gridY <= endGridY; y += gridHeight, gridY++) {
                    int x = startX;
                    int gridX = startGridX;
                    for (; gridX <= endGridX; x += gridWidth, gridX++) {
                        g.DrawImage(//
                                ((HLTile) ownerWorld.tiles.items[ownerWorld.Grid_GetTileType(gridX, gridY)]).image,//
                                x,//
                                y,//
                                ownerWorld.Grid_GetTileTrans(gridX, gridY)//
                        );
                    }
                }
            } else {
                // g.FillRect(0, 0, HLScreen.width, HLScreen.height, backColor);
            }

            if (renderMap) {
                startGridY -= ownerWorld.mapSpriteMaxCheckToUp;
                if (startGridY < 0) {
                    startGridY = 0;
                }

                endGridY += ownerWorld.mapSpriteMaxCheckToDown;
                if (endGridY >= ownerWorld.gridCountV) {
                    endGridY = ownerWorld.gridCountV - 1;
                }

                startGridX -= ownerWorld.mapSpriteMaxCheckToLeft;
                if (startGridX < 0) {
                    startGridX = 0;
                }

                endGridX += ownerWorld.mapSpriteMaxCheckToRight;
                if (endGridX >= ownerWorld.gridCountH) {
                    endGridX = ownerWorld.gridCountH - 1;
                }
            }
            // ?????????????0?????
            if (ownerWorld.SPRITE_PRI_START <= SPRITE_PRI_LOWEST && SPRITE_PRI_LOWEST <= ownerWorld.SPRITE_PRI_END) {
                RenderSprites(g, SPRITE_PRI_LOWEST);
            }
            // ?????????????0???????
            if (renderMap) {
                RenderMapSprites(g, MAPSPRITE_PRI_LOW, startGridX, startGridY, endGridX, endGridY, clipGridX0, clipGridX1, clipGridY0, clipGridY1);
            }
            // ?????????????1?????
            if (ownerWorld.SPRITE_PRI_START <= SPRITE_PRI_LOWER && SPRITE_PRI_LOWER <= ownerWorld.SPRITE_PRI_END) {
                RenderSprites(g, SPRITE_PRI_LOWER);
            }
            // ????????????1???????????????2?????,????????????
            if (renderMap) {
                HLList spriteGroup = spriteGroups[SPRITE_PRI_NORMAL];

                if (ownerWorld.SPRITE_PRI_START <= SPRITE_PRI_NORMAL && SPRITE_PRI_NORMAL <= ownerWorld.SPRITE_PRI_END && spriteGroup.items.length > 0) {
                    int tempXOfScreen = offsetX - xOfWorld;
                    int tempYOfScreen = offsetY - yOfWorld;

                    int gridY = startGridY;
                    int gridHeightFP = ownerWorld.gridHeight << BITS;
                    int yFP = (startGridY * ownerWorld.gridHeight << BITS) + (ownerWorld.gridHeight << (BITS - 1));
                    int spriteIndex = 0;

                    HLSprite sprite = (HLSprite) spriteGroup.items[spriteIndex];
                    while (gridY <= endGridY) {
                        while (sprite.yFP < yFP) {
                            if (ownerWorld.WORLD_IS_3D) {
                                sprite.Render3D(g, tempXOfScreen, tempYOfScreen);
                            } else {
                                sprite.Render2D(g, tempXOfScreen, tempYOfScreen);
                            }
                            spriteIndex++;
                            if (spriteIndex < spriteGroup.items.length) {
                                sprite = (HLSprite) spriteGroup.items[spriteIndex];
                            } else {
                                sprite = null;
                                break;
                            }
                        }
                        if (sprite == null) {
                            break;
                        }

                        if (ownerWorld.IS_PRIORITY_NORMAL_MAPSPRITE_ENABLE) {
                            RenderMapSprites(g, MAPSPRITE_PRI_NORMAL, startGridX, gridY, endGridX, gridY, clipGridX0, clipGridX1, clipGridY0, clipGridY1);
                        }

                        gridY++;
                        yFP += gridHeightFP;

                    }
                    if (sprite == null && ownerWorld.IS_PRIORITY_NORMAL_MAPSPRITE_ENABLE) {
                        RenderMapSprites(g, MAPSPRITE_PRI_NORMAL, startGridX, gridY, endGridX, endGridY, clipGridX0, clipGridX1, clipGridY0, clipGridY1);
                    } else {
                        for (; spriteIndex < spriteGroup.items.length; spriteIndex++) {
                            if (ownerWorld.WORLD_IS_3D) {
                                ((HLSprite) spriteGroup.items[spriteIndex]).Render3D(g, tempXOfScreen, tempYOfScreen);
                            } else {
                                ((HLSprite) spriteGroup.items[spriteIndex]).Render2D(g, tempXOfScreen, tempYOfScreen);
                            }
                        }
                    }
                } else if (ownerWorld.IS_PRIORITY_NORMAL_MAPSPRITE_ENABLE)// ???????????????????????????????????????
                {
                    RenderMapSprites(g, MAPSPRITE_PRI_NORMAL, startGridX, startGridY, endGridX, endGridY, clipGridX0, clipGridX1, clipGridY0, clipGridY1);
                }
            } else if (ownerWorld.SPRITE_PRI_START <= SPRITE_PRI_NORMAL && SPRITE_PRI_NORMAL <= ownerWorld.SPRITE_PRI_END) {
                // ?????????????????????????????
                RenderSprites(g, SPRITE_PRI_NORMAL);
            }
            // ?????????????3?????
            if (ownerWorld.SPRITE_PRI_START <= SPRITE_PRI_HIGHER && SPRITE_PRI_HIGHER <= ownerWorld.SPRITE_PRI_END) {
                RenderSprites(g, SPRITE_PRI_HIGHER);
            }
            // ?????????????2???????
            if (renderMap && ownerWorld.IS_PRIORITY_HIGH_MAPSPRITE_ENABLE) {
                RenderMapSprites(g, MAPSPRITE_PRI_HIGH, startGridX, startGridY, endGridX, endGridY, clipGridX0, clipGridX1, clipGridY0, clipGridY1);
            }
            // ?????????????4?????
            if (ownerWorld.SPRITE_PRI_START <= SPRITE_PRI_HIGHEST && SPRITE_PRI_HIGHEST <= ownerWorld.SPRITE_PRI_END) {
                RenderSprites(g, SPRITE_PRI_HIGHEST);
            }
        }

        g.RestoreClip();

        if (showWidth < width) {
            g.FillRect(xOfScreen, realYOfScreen, xOfFrame, height - yOfFrame, backColor);
            g.FillRect(realXOfScreen + showWidth, yOfScreen, width - xOfFrame - showWidth, yOfFrame + showHeight, backColor);
        }
        if (showHeight < height) {
            g.FillRect(xOfScreen, yOfScreen, xOfFrame + showWidth, yOfFrame, backColor);
            g.FillRect(realXOfScreen, realYOfScreen + showHeight, width - xOfFrame, height - yOfFrame - showHeight, backColor);
        }
    }

    // Render
    public void Render(HLGraphics g) {
        if (shakeTimer > 0) {
            int shakeOffset = HLMath.GetShakePos(shakeOffsetMax, startDirect, shakeTimerMax, shakeTimer);
            if (startDirect % 2 == 0) {
                RenderEx(g, 0, shakeOffset);
            } else {
                RenderEx(g, shakeOffset, 0);
            }
            shakeTimer--;
            startDirect = (byte) -startDirect;
        } else {
            RenderEx(g, 0, 0);
        }
    }

    // DrawMapSpriteToScreen
    void DrawMapSpriteToScreen(HLGraphics g, int offsetX, int offsetY, int startGridX, int startGridY, int endGridX, int endGridY, int priority, HLSprite sprite) {
        if (CARMACK_ENABLE) {
            if (renderMap) {
                int clipX0 = startGridX;
                int clipX1 = endGridX;
                int clipY0 = startGridY;
                int clipY1 = endGridY;

                startGridY -= ownerWorld.mapSpriteMaxCheckToUp;
                if (startGridY < 0) {
                    startGridY = 0;
                }
                int yStart = offsetY + startGridY * ownerWorld.gridHeight;

                endGridY += ownerWorld.mapSpriteMaxCheckToDown;
                if (endGridY >= ownerWorld.gridCountV) {
                    endGridY = ownerWorld.gridCountV - 1;
                }

                startGridX -= ownerWorld.mapSpriteMaxCheckToLeft;
                if (startGridX < 0) {
                    startGridX = 0;
                }

                int xStart = offsetX + startGridX * ownerWorld.gridWidth;
                endGridX += ownerWorld.mapSpriteMaxCheckToRight;
                if (endGridX >= ownerWorld.gridCountH) {
                    endGridX = ownerWorld.gridCountH - 1;
                }
                while (startGridY <= endGridY) {
                    int x = xStart;
                    int curGridX = startGridX;
                    // HLGrid * line = ownerWorld.gridRows[startGridY];
                    while (curGridX <= endGridX) {
                        if (ownerWorld.Grid_GetHasMapSprite(curGridX, startGridY)) {
                            int tempMapSpriteType = ownerWorld.Grid_GetMapSpriteType(curGridX, startGridY);
                            HLMapSprite tempMapSpriteModel = (HLMapSprite) ownerWorld.mapSprites.items[tempMapSpriteType];
                            if (priority == tempMapSpriteModel.pri && curGridX - tempMapSpriteModel.occupyH <= clipX1 && curGridX + tempMapSpriteModel.gridCountH + tempMapSpriteModel.occupyH > clipX0 && startGridY - tempMapSpriteModel.occupyV <= clipY1 && startGridY + tempMapSpriteModel.gridCountV > clipY0) {
                                int trans = ownerWorld.Grid_GetMapSpriteTrans(curGridX, startGridY);
                                if (ownerWorld.WORLD_IS_3D) {
                                    /*
                                     * if( (priority != MAPSPRITE_PRI_NORMAL) ||
                                     * (sprite.z <
                                     * ownerWorld.cdGroupAllTrans.items
                                     * [trans][tempMapSpriteModel.cdType].z +
                                     * ownerWorld.cdGroupAllTrans.items[trans][
                                     * tempMapSpriteModel.cdType].length ) )
                                     */
                                }
                                {
                                    g.DrawImageAdjustable(tempMapSpriteModel.image, x, yStart, ownerWorld.gridWidth * tempMapSpriteModel.gridCountH, ownerWorld.gridHeight * tempMapSpriteModel.gridCountV - tempMapSpriteModel.offset, trans, HCENTER_BOTTOM);
                                }
                            }
                        }
                        x += ownerWorld.gridWidth;
                        curGridX++;
                    }
                    yStart += ownerWorld.gridHeight;
                    startGridY++;
                }
            }
        }
    }

    // RenderMapSprites
    void RenderMapSprites(HLGraphics g, int priority, int startGridX, int startGridY, int endGridX, int endGridY, int clipGridX0, int clipGridX1, int clipGridY0, int clipGridY1) {
        int xStart = startGridX * ownerWorld.gridWidth - xOfWorld + realXOfScreen;
        int gridY = startGridY;
        int y = startGridY * ownerWorld.gridHeight - yOfWorld + realYOfScreen + shakeOffsetY;
        for (; gridY <= endGridY; gridY++, y += ownerWorld.gridHeight) {
            // HLGrid * line = ownerWorld.gridRows[gridY];
            int gridX = startGridX;
            int x = xStart + shakeOffsetX;
            for (; gridX <= endGridX; gridX++, x += ownerWorld.gridWidth) {
                if (ownerWorld.Grid_GetHasMapSprite(gridX, gridY)) {
                    int tempMapSpriteType = ownerWorld.Grid_GetMapSpriteType(gridX, gridY);
                    HLMapSprite tempMapSpriteModel = (HLMapSprite) ownerWorld.mapSprites.items[tempMapSpriteType];

                    if (priority == tempMapSpriteModel.pri //
                            && gridX - tempMapSpriteModel.occupyH <= clipGridX1 //
                            && gridX + tempMapSpriteModel.gridCountH + tempMapSpriteModel.occupyH > clipGridX0 //
                            && gridY - tempMapSpriteModel.occupyV <= clipGridY1 //
                            && gridY + tempMapSpriteModel.gridCountV > clipGridY0

                    ) {
                        HLImage image = tempMapSpriteModel.image;

                        int trans = ownerWorld.Grid_GetMapSpriteTrans(gridX, gridY);

                        g.DrawImage(image, //
                                x + ((ownerWorld.gridWidth * tempMapSpriteModel.gridCountH - (trans >= 4 ? image.GetHeight() : image.GetWidth())) >> 1), //
                                y + (ownerWorld.gridHeight * tempMapSpriteModel.gridCountV - tempMapSpriteModel.offset) - (trans >= 4 ? image.GetWidth() : image.GetHeight()), //
                                trans);
                        // HLGraphics.DrawRegionEX(g, image, 0, 0,
                        // image.getWidth(), image.getHeight(), x +
                        // ((ownerWorld.gridWidth *
                        // tempMapSpriteModel.gridCountH - (trans >= 4 ?
                        // image.getHeight() : image.getWidth())) >> 1), y +
                        // (ownerWorld.gridHeight *
                        // tempMapSpriteModel.gridCountV -
                        // tempMapSpriteModel.offset) - (trans >= 4 ?
                        // image.getWidth() : image.getHeight()), trans);
                    }
                }
            }
        }
    }

    // RenderSprites
    void RenderSprites(HLGraphics g, int priority) {
        int tempXOfScreen = realXOfScreen - xOfWorld + shakeOffsetX;
        int tempYOfScreen = realYOfScreen - yOfWorld + shakeOffsetY;
        HLList spriteGroup = spriteGroups[priority];
        for (int i = 0; i < spriteGroup.items.length; i++) {
            if (ownerWorld.WORLD_IS_3D) {
                ((HLSprite) spriteGroup.items[i]).Render3D(g, tempXOfScreen, tempYOfScreen);
            } else {
                ((HLSprite) spriteGroup.items[i]).Render2D(g, tempXOfScreen, tempYOfScreen);
            }
        }
    }
}
